﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Threading;
using System.Xml.Serialization;

namespace iTunesFastForward
{

    public class Shortcut : Component, IMessageFilter
    {

        [field:XmlIgnore]
        public event EventHandler KeyPressed;

        public int Value { get; set; }
        public Keys Modifiers { get; set; }
        public Keys Keys { get; set; }
        public string Name { get; set; }
        public string Representation { get; set; }

        [XmlIgnore]
        public bool HasSeparatorBefore { get; set; }

        [XmlIgnore]
        public int HotKeyID { get; set; }

        [XmlIgnore]
        public IntPtr Handle { get; set; }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool RegisterHotKey(IntPtr hwnd, int id, int fsModifiers, int vk);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern bool UnregisterHotKey(IntPtr hwnd, int id);

        /// <summary>
        /// Method for generating a global id
        /// </summary>
        /// <param name="lpString"></param>
        /// <returns></returns>
        [DllImport("kernel32.dll")]
        private static extern short GlobalAddAtom(string lpString);

        [DllImport("kernel32.dll")]
        private static extern short GlobalDeleteAtom(short nAtom);

        // définition des poids pour les modifiers
        [Flags()]
        enum KeyModifiers
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            Windows = 8
        }

        public Shortcut() : base()
        {
        }

        public void RegisterShortCut()
        {
            // récupérer l'id
            if (HotKeyID == 0)
                HotKeyID = GlobalAddAtom("iTunesFastForward." + Name);
            if (HotKeyID == 0)
                throw new ApplicationException("Unable to create hotkey id. Error code:" + Marshal.GetLastWin32Error().ToString());

            UnregisterHotKey(Handle, HotKeyID);

            // calculer le modifier
            KeyModifiers modifiers = KeyModifiers.None;
            if ((Modifiers | Keys.Alt) == Modifiers)
                modifiers |= KeyModifiers.Alt;
            if ((Modifiers | Keys.Control) == Modifiers)
                modifiers |= KeyModifiers.Control;
            if ((Modifiers | Keys.Shift) == Modifiers)
                modifiers |= KeyModifiers.Shift;
            if ((Modifiers | Keys.LWin) == Modifiers)
                modifiers |= KeyModifiers.Windows;


            if (!RegisterHotKey(Handle, HotKeyID, (int)modifiers, Value))
            {
                throw new ApplicationException("Unable to register hotkey. Error code:" + Marshal.GetLastWin32Error().ToString());
            }

            Application.AddMessageFilter(this);
        }

        public void UnregisterShortCut()
        {
            // unregister the hotkey
            if (!Handle.Equals(IntPtr.Zero))
            {
                UnregisterHotKey(Handle, HotKeyID);
                Handle = IntPtr.Zero;
                Keys = Keys.None;
                Modifiers = Keys.None;
                HasSeparatorBefore = false;
                Value = 0;
            }

            // delete the global atom
            if (HotKeyID != 0)
            {
                GlobalDeleteAtom((short)HotKeyID);
                HotKeyID = 0;
            }

            Application.RemoveMessageFilter(this);
        }

        public void OnKeyPressed()
        {
            if (KeyPressed != null)
                KeyPressed(this, EventArgs.Empty);
        }

        #region IMessageFilter Members

        const int WM_HOTKEY = 0x0312;
        bool IMessageFilter.PreFilterMessage(ref Message m)
        {
            switch (m.Msg)
            {
                case WM_HOTKEY:
                    if (Handle == m.HWnd)
                    {
                        OnKeyPressed();
                        return true;
                    }
                    break;
            }
            return false;
        }

        #endregion
    }
}
